package com.ym.medical.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.ym.base.enums.FlagEnum;
import com.ym.common.constant.Constants;
import com.ym.common.constant.DictEnum;
import com.ym.core.annotation.Locker;
import com.ym.core.exception.BusinessException;
import com.ym.core.rabbit.IMessageSenderSV;
import com.ym.core.redis.RedisKeyEnum;
import com.ym.core.utils.tkmybatis.BaseSVImpl;
import com.ym.core.utils.tkmybatis.TK;
import com.ym.medical.dao.AddressGroupDao;
import com.ym.medical.dao.AddressListDao;
import com.ym.medical.dao.DoctorPhoneSettingDao;
import com.ym.medical.dao.DoctorServiceItemDao;
import com.ym.medical.dao.DoctorServicePriceDao;
import com.ym.medical.dao.DoctorStudioDao;
import com.ym.medical.dao.InquiryAnnexDao;
import com.ym.medical.dao.PhoneRuleDao;
import com.ym.medical.dao.TextRuleDao;
import com.ym.medical.domain.entity.*;
import com.ym.medical.domain.param.DoctorPhoneSettingModel;
import com.ym.medical.domain.param.InquiryOrderParam;
import com.ym.medical.domain.param.PhoneRuleModel;
import com.ym.medical.domain.param.TextRuleParam;
import com.ym.medical.domain.vo.DoctPhoneRuleItemVo;
import com.ym.medical.domain.vo.DoctorServiceItemVO;
import com.ym.medical.domain.vo.DoctorServicePriceVo;
import com.ym.medical.domain.vo.OpenServiceListVo;
import com.ym.medical.domain.vo.OrderVo;
import com.ym.medical.domain.vo.PhoneAppointmentTimeVo;
import com.ym.medical.enums.*;
import com.ym.medical.service.*;
import com.ym.medical.service.task.UnPayCancelOrderTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * 电话问诊规则Service业务层处理
 *
 * @author ym
 * @date 2020-09-14
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DoctorServiceItemSVImpl extends BaseSVImpl<DoctorServiceItemEntity, DoctorServiceItemDao> implements IDoctorServiceItemSV {
	private static Logger logger = LoggerFactory.getLogger(DoctorServiceItemSVImpl.class);

	@Autowired
	private TextRuleDao textRuleDao;

	@Autowired
	private DoctorServicePriceDao doctorServicePriceDao;

	@Autowired
	private DoctorPhoneSettingDao doctorPhoneSettingDao;

	@Autowired
	private PhoneRuleDao phoneRuleDao;

	@Autowired
	private ISysCodeRuleSV iGenerateCodeRuleSV;

	@Autowired
	private ISysConfigSV sysConfigSV;

	@Autowired
	private IOrderFlowRecordSV iOrderFlowRecordSV;

	@Autowired
	private DoctorStudioDao doctorStudioDao;

	@Autowired
	private AddressGroupDao addressGroupDao;

	@Autowired
	private AddressListDao addressListDao;

	@Autowired
	private InquiryAnnexDao inquiryAnnexDao;

	@Autowired
	private IStudioPersonnelSV iStudioPersonnelSV;

	@Autowired
	private IInquiryOrderSV iInquiryOrderSV;

	@Autowired
	private ISysDictSV sysDictDao;

	@Autowired
	private IDoctorVideoSettingSV doctorVideoSettingSV;

	@Autowired
	private IMessageSenderSV messageSenderSV;

	@Autowired
	private ICouponReceiveRecordSV receiveRecordSV;

	@Autowired
	private ICouponSV iCouponSV;

	@Autowired
	private ISysDictSV sysDictSV;

	/**
	 * 医生服务项查询
	 *
	 * @param doctId
	 * @return
	 */
	@Override
	public List<DoctorServiceItemEntity> getSrviceItem(Long doctId) {
		List<DoctorServiceItemEntity> doctorServiceItems = mapper.selectByDoctId(doctId);
		return doctorServiceItems;
	}

	/***
	 * 医生服务项启用失效
	 * @param doctorServiceItem
	 * @return
	 */
	@Override
	public Map<String, Object> disOrEnableItem(DoctorServiceItemEntity doctorServiceItem) {
		Map<String, Object> map = new HashMap<>();
		int rows = 0;
		Long docServId = 0L;
		//id判断医生是否有该条服务项
		if (null == doctorServiceItem.getId()) {
			mapper.insertSelective(doctorServiceItem);
			docServId = doctorServiceItem.getId();

		} else {
			rows = mapper.updateByPrimaryKeySelective(doctorServiceItem);
		}
		map.put("docServId", docServId);
		map.put("rows", rows);
		return map;
	}

	/**
	 * 医生服务图文规则对应单价查询
	 *
	 * @param doctId
	 * @return
	 */
	@Override
	public List<DoctorServicePriceVo> selectServicePrice(Long doctId) {
		List<DoctorServicePriceVo> doctorServicePrice = doctorServicePriceDao.selectServicePrice(doctId);
		return doctorServicePrice;
	}

	/**
	 * 查询图文默认的规则
	 *
	 * @return
	 */
	@Override
	public List<TextRuleEntity> selectDefaultItem() {
		List<TextRuleEntity> textRules = textRuleDao.selectDefaultItem();
		return textRules;
	}

	/**
	 * 医生图文设置信息
	 *
	 * @param doctorServiceItem
	 * @param model
	 * @return
	 */
	@Override
	public int graphicSet(DoctorServiceItemEntity doctorServiceItem, TextRuleParam model) {
		/*  判断图文设置是否是第一次设置 是则插入  不是则更改
		 *  第一次设置则立即生效 第二次则是凌晨生效 条件(图文设置主键 id null)
		 */
		int rows = 0;
		Long docServId = 0L;
		//id判断医生是否有该条服务项
		if (doctorServiceItem.getId() != null) {
			mapper.updateByPrimaryKeySelective(doctorServiceItem);
			docServId = doctorServiceItem.getId();
			model.setDocServId(docServId);
		} else {
			mapper.insertSelective(doctorServiceItem);
			docServId = doctorServiceItem.getId();
			model.setDocServId(docServId);
		}
		model.setIsDefault("00");
		DoctorServicePriceVo vPrice =
				doctorServicePriceDao.textValidServicePrice(model.getPriceId());
		//未改变值不执行
		if (model.getPriceId() != null && vPrice.getTrRound().equals(model.getTrRound()) && vPrice.getDspPrice().doubleValue() == model.getDspPrice().doubleValue()) {
			return 1;
		}
		boolean doNothing = null == model.getId()
				&& null == model.getPriceId() && BigDecimal.ZERO.equals(model.getDspPrice()) && 0 == model.getTrRound();
		if (doNothing) {
			return 1;
		}
		//图文设置方法  注释
		//textSet(model);

		/*
		 * 1.1 判断是否是第一次设置单价(条件 规则id !null 单价id null) 规则id 价钱id 都空
		 * 勿删
		 */
		boolean flag = model.getId() != null
				&& null == model.getPriceId();
		if (flag) {

			DoctorServicePriceEntity servicePrice2 = new DoctorServicePriceEntity();
			//生效
			servicePrice2.setState(FlagEnum.IS.getKey());
			servicePrice2.setDoctId(doctorServiceItem.getDoctId());
			servicePrice2.setSeriLabel(DoctorServiceItemEnum.BY_INQUIRING.getKey());
			servicePrice2.setRuleId(model.getId());
			servicePrice2.setDspPrice(model.getDspPrice());
			servicePrice2.setCreateTime(new Date());
			servicePrice2.setValidTime(new Date());
			rows = doctorServicePriceDao.insertSelective(servicePrice2);
			return rows;
		}

		/*1.2判断是否是新增规则与单价  (新增条件规则id null 单价id null)
		 * 新增的规则及单价 当前时间生效
		 */
		boolean flag2 = null == model.getId()
				&& null == model.getPriceId();
		if (flag2) {
			//查询规则是否存在
			long textRuleId = ruleId(model);
			//同时新增价钱表数据   非空判断下,防止用户没有设置单价
			if (null == model.getDspPrice()) {
				throw new BusinessException("请设置问诊价格");
			} else {
				//添加单价表数据 生效时间是当前时间 状态01
				//Long textRuleId = model.getId();
				DoctorServicePriceEntity servicePrice = new DoctorServicePriceEntity();
				servicePrice.setRuleId(textRuleId);
				servicePrice.setDoctId(doctorServiceItem.getDoctId());
				servicePrice.setSeriLabel(DoctorServiceItemEnum.BY_INQUIRING.getKey());
				servicePrice.setDspPrice(model.getDspPrice());
				servicePrice.setCreateTime(new Date());
				servicePrice.setValidTime(new Date());
				servicePrice.setState("01");
				rows = doctorServicePriceDao.insertSelective(servicePrice);
			}
			return rows;
		} else {

			/*
			 *1.1 判断是更改单价 (条件  规则id !null 单价id !null  服务项id !=null)
			 */

			//查询当前规则对用价钱   查询当下修改价格是否是第一次修改  第一次则结果为null 第二次则不为null  之前(待生效)
			DoctorServicePriceVo price =
					doctorServicePriceDao.selectTextNoEffectPrice(doctorServiceItem.getDoctId(), model.getId());
			//在生效的 model.getPriceId() 生效的单价id
			DoctorServicePriceVo beforePrice =
					doctorServicePriceDao.textValidServicePrice(model.getPriceId());

			DoctorServicePriceEntity servicePrice = new DoctorServicePriceEntity();

			if (null == model.getId() && model.getPriceId() != null && price != null) {
				//查询规则是否存在
				long textRuleId = ruleId(model);
				//textRuleDao.insertSelective(model);
				servicePrice.setRuleId(textRuleId);
				servicePrice.setId(price.getId());
				servicePrice.setDspPrice(model.getDspPrice());
				rows = doctorServicePriceDao.updateByPrimaryKeySelective(servicePrice);
				return rows;
			}

			//第一次更改在使用中的单价  需要新增一条并设置生效凌晨 如果价钱相等不操作
			//查询规则表
			//TextRule t = textRuleDao.selectById(beforePrice.getRuleId());
//			boolean falg = beforePrice != null && null == price
//					&& (model.getDspPrice().doubleValue() != beforePrice.getDspPrice().doubleValue()
//					|| !model.getTrRound().equals(t.getTrRound()));
			boolean flag3 = beforePrice != null && null == price;
			if (flag3) {
				if (!model.getTrRound().equals(beforePrice.getTrRound()) && model.getId() == null) {
					//查询规则是否存在
					long textRuleId = ruleId(model);
//					textRuleDao.insertSelective(model);
//					long rulId = model.getId();
					servicePrice.setRuleId(textRuleId);
				} else {
					servicePrice.setRuleId(model.getId());
				}
				//修改单价时，则之前录失效时间改为23:59:59，；
				beforePrice.setInvalidTime(getInvalidTime());
				//更改上次失效时间为 23:59:58
				doctorServicePriceDao.updateByPrimaryKeySelective(beforePrice);

				//并新增一条新纪录，并将生效时间设置为次日凌晨00:00:00 状态置为失效 "00"
				servicePrice.setDoctId(doctorServiceItem.getDoctId());
				servicePrice.setSeriLabel(DoctorServiceItemEnum.BY_INQUIRING.getKey());
				servicePrice.setDspPrice(model.getDspPrice());

				servicePrice.setState("00");
				servicePrice.setValidTime(getValidTime());
				rows = doctorServicePriceDao.insertSelective(servicePrice);
			}
			//第二次设置单价 直接按规则id和服务id修改
			if (price != null) {

				if (model.getTrRound().equals(beforePrice.getTrRound())) {
					//textRuleDao.insertSelective(model);
					servicePrice.setRuleId(price.getRuleId());
				} else {
					servicePrice.setRuleId(model.getId());
				}

				if (model.getDspPrice().doubleValue() == beforePrice.getDspPrice().doubleValue()) {
					servicePrice.setDspPrice(price.getDspPrice());
				} else {
					servicePrice.setDspPrice(model.getDspPrice());
				}
				//当前
				servicePrice.setId(price.getId());
				rows = doctorServicePriceDao.updateByPrimaryKeySelective(servicePrice);
			}

		}
		return rows;
	}

	@Override
	public List<TextRuleEntity> getTextRules() {
		return null;
	}

	/**
	 * 固定生效时间 > 失效
	 */
	@Override
	public Date getValidTime() {
		TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		Date date = calendar.getTime();
		return date;
	}

	/**
	 * 固定失效时间  第二天凌晨
	 */
	@Override
	public Date getInvalidTime() {
		TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		Date date2 = calendar.getTime();
		return date2;
	}

	/**
	 * 图文规则id判断重复值
	 *
	 * @param model
	 * @return
	 */
	private long ruleId(TextRuleParam model) {
		long ruleId = 0;
		//查询规则是否存在
		PageHelper.startPage(1, 1);
		List<TextRuleEntity> rule = textRuleDao.select(TextRuleEntity.builder().trType(RuleTypeEnum.THE_REGULAR_RULES.getKey()).trRound(model.getTrRound()).build());
		PageHelper.clearPage();
		if (null == rule) {
			model.setIsDefault("00");
			model.setTrType("01");
			textRuleDao.insertSelective(model.covert());
			ruleId = model.getId();
		} else {
			ruleId = rule.get(0).getId();
		}
		return ruleId;
	}

	/**
	 * 8
	 * 删除图文规则
	 *
	 * @param textRuleId
	 * @return
	 */
	@Override
	public int deleteTextRule(Long textRuleId) {
		int rows = textRuleDao.deleteByPrimaryKey(textRuleId);
		//同时删除对应的规则单价
		doctorServicePriceDao.deleteByRuleId(textRuleId);
		return rows;
	}


	/***
	 * 规则对应单价列表
	 * 改表后医生id查询)
	 * @param doctId
	 * @return
	 */
	@Override
	public List<DoctorServicePriceVo> selectPhoneRulePrices(Long doctId) {
		List<DoctorServicePriceVo> PhoneRulePrices = doctorServicePriceDao.selectPhoneRulePrices(doctId);

		return PhoneRulePrices;
	}

	@Override
	public Map<String, Object> phoneAppointmentTime(Long doctServId) {
		return null;
	}

	@Override
	public OrderVo generateOrders(InquiryOrderParam inquiryOrderModel) {
		// 1.订单基础信息生成
		String ioNum = iGenerateCodeRuleSV.createCode(CodeRuleEnum.VISIT_ORDER);
		inquiryOrderModel.setIoNum(ioNum);
		//判断优惠券
		couponUse(inquiryOrderModel);
		inquiryOrderModel.setPaymentState(InquiryOrderPaymentStateEnum.TO_BE_PAID.getKey());
		inquiryOrderModel.setCreateTime(new Date());
		inquiryOrderModel.setIoState(InquiryOrderStateEnum.WAIT_EFFECTIVE.getKey());
		inquiryOrderModel.setRuleId(inquiryOrderModel.getPriceId());

		// 2.订单流转表记录
		DoctorStudioEntity doctorStudio = doctorStudioDao.selectOne(DoctorStudioEntity.builder().belongPerson(inquiryOrderModel.getDoctId()).build());
		Long doctorStudioId = doctorStudio == null ? null : doctorStudio.getId();
		OrderFlowRecordEntity orderFlowRecord = new OrderFlowRecordEntity();
		orderFlowRecord.setType(OrderFlowRecordTypeEnum.SPECIALIZED_SUBJECT.getKey());
		orderFlowRecord.setStatus(OrderFlowRecordSatusEnum.NOT_ROB_SINGLE.getKey());
		orderFlowRecord.setDoctorOrderTime(new Date());
		// 2.1设置流转人员，主要判定设置orderFlowRecord的流转人.如果需要放入订单池，返回workId
		InquiryOrderIoTypeEnum enumByCode = DictEnum.valueOfEnum(InquiryOrderIoTypeEnum.class, inquiryOrderModel.getIoType());
		switch (enumByCode) {
			case BY_CONSULTING:
				OrderVo orderVo = byInquiringSet(inquiryOrderModel, orderFlowRecord, doctorStudioId);
				if (orderVo != null) {
					orderVo.setOrder(true);
					return orderVo;
				}
				break;
			case TELEPHONE_COUNSELING:
				callPhysicianVisitsSet(inquiryOrderModel, orderFlowRecord, doctorStudioId);
				break;
			case PRVIVATE_DOCTOR:
				// 暂无
				break;
			default:
				throw new BusinessException("超出业务范畴");

		}

		iInquiryOrderSV.insert(inquiryOrderModel.covert());
		orderFlowRecord.setOrderId(inquiryOrderModel.getId());
		iOrderFlowRecordSV.save(orderFlowRecord);

		// 3.问诊附件表信息保存
		if (!StringUtils.isEmpty(inquiryOrderModel.getFileInforId())) {
			InquiryAnnexEntity inquiryAnnex = new InquiryAnnexEntity();
			inquiryAnnex.setFileInforId(inquiryOrderModel.getFileInforId());
			inquiryAnnex.setIoNum(ioNum);
			inquiryAnnex.setIoId(inquiryOrderModel.getId());
			inquiryAnnexDao.insertSelective(inquiryAnnex);
		}

		// 4.如果是电话、视频，需要设置超时未支付取消订单操作，是否可预约时间。
		JSONObject params = new JSONObject();
		params.put("id", inquiryOrderModel.getId());
		UnPayCancelOrderTask unPayCancelOrderTask = new UnPayCancelOrderTask("下单后不支付自动取消订单", TimeUnit.MINUTES.toMillis(orderCancelTime()), params);
		messageSenderSV.sendDelayTask(unPayCancelOrderTask);
		if (inquiryOrderModel.getRelId() != null) {
			CouponReceiveRecordEntity receiveRecord = new CouponReceiveRecordEntity();
			receiveRecord.setId(inquiryOrderModel.getRelId());
			receiveRecord.setStateTime(new Date());
			//更改优惠券领取记录已使用
			receiveRecord.setUserState(CouponUseStateEnum.HAS_BEEN_USED.getKey());
			receiveRecordSV.updateById(receiveRecord);
		}
		logger.info("===============>订单下单成功: 订单id为:" + inquiryOrderModel.getId() + "订单 :" + inquiryOrderModel.toString());


		inquiryOrderModel.setOrderId(inquiryOrderModel.getId());
		InquiryOrderEntity covert = inquiryOrderModel.covert();
		OrderVo orderVo = new OrderVo();
		BeanUtils.copyProperties(covert, orderVo);
		return orderVo;
	}

	/**
	 * 获取订单自动取消时间
	 *
	 * @return
	 */
	private long orderCancelTime() {
		Long orderCompletionTime = 10L;
		Long valueByKey = sysConfigSV.getValueByKey(Constants.SysConfigKey.ORDER_AUTOCANCEL_TIME, Long::new);
		if (valueByKey != null) {
			return valueByKey;
		}
		return orderCompletionTime;
	}


	/**
	 * 图文咨询设置，此处主要判定设置orderFlowRecord的流转人
	 *
	 * @param inquiryOrderModel 订单信息
	 * @param orderFlowRecord   订单流转信息
	 * @param doctorStudioId    患者问诊医生的工作室ID
	 */
	private OrderVo byInquiringSet(InquiryOrderParam inquiryOrderModel, OrderFlowRecordEntity orderFlowRecord, Long doctorStudioId) {
		Long doctId = inquiryOrderModel.getDoctId();
		Long userId = inquiryOrderModel.getUserId();

		//下单前判断
		OrderVo orderVo = iInquiryOrderSV.samePatientLimit(inquiryOrderModel.getPatientId(), doctId);
		if (orderVo != null) {
			return orderVo;
		}

		// 1.1单价id查询的单价
		DoctorServicePriceEntity price = doctorServicePriceDao.selectByPrimaryKey(inquiryOrderModel.getPriceId());
		//1.2. 判断患者义诊过的次数 是否义诊过该医生  医生义诊次数
		if (inquiryOrderModel.getIsClinic()) {
			checkClinic(inquiryOrderModel.getUserId(), inquiryOrderModel.getDoctId(), price.getRuleId());
		}

		//查询工作室成员
		List<StudioPersonnelEntity> personnels = iStudioPersonnelSV.selectPersons(doctId);
		Long dsId = null;

		if (personnels.size() == 2) {
			dsId = personnels.get(1).getDsId();
		}
		List<OrderVo> order = iInquiryOrderSV.selectRepeatOrder(dsId, doctId, userId, inquiryOrderModel.getPatientId());
		if (order != null && !order.isEmpty()) {
			return order.get(0);
		}

		//1.继续问诊
		if (InquiryOrderSourceEnum.CONTINUE_CONSULT.getKey().equals(inquiryOrderModel.getOrderSource())) {
			if (inquiryOrderModel.getOrderId() == null) {
				throw new BusinessException("继续咨询，上一次咨询订单ID不能为空！");
			}
			OrderFlowRecordEntity flowRecord = iOrderFlowRecordSV.findNewByOrderId(inquiryOrderModel.getOrderId());
			Long doctorDsId = flowRecord.getDoctorDsId();
			Long doctOldId = flowRecord.getDoctorId();
			// 1.1 判定上一单是否有工作室，没有工作室，则直接设置上一单的医生ID
			if (doctorDsId == null) {
				orderFlowRecord.setDoctorId(doctOldId);
				return null;
			}
			//1.2判定该继续咨询的医生，是否被停诊，如果停诊给工作室
			StudioPersonnelEntity personnel = iStudioPersonnelSV.selectOne(StudioPersonnelEntity.builder().dsId(doctorDsId).doctId(doctOldId).build());
			if (FlagEnum.NO.getKey().equals(personnel.getAdmsStateStudio())) {
				// 停诊
				orderFlowRecord.setDoctorDsId(doctorDsId);
				logger.info("继续问诊，图文问诊订单进入工作室");
			} else {
				// 接诊
				orderFlowRecord.setDoctorId(doctOldId);
				orderFlowRecord.setDoctorDsId(doctorDsId);
				logger.info("继续问诊，图文问诊订单继续给上个医生");
			}
		} else if (InquiryOrderSourceEnum.LOOKING_FOR_A_DOCTOR.getKey().equals(inquiryOrderModel.getOrderSource())) {

			if (doctorStudioId == null) {
				orderFlowRecord.setDoctorId(inquiryOrderModel.getDoctId());
			} else {
				//找医生,如果该医生有工作室，只指定工作室ID
				orderFlowRecord.setDoctorDsId(doctorStudioId);
			}
		}
		return null;
	}

	/**
	 *  下单前判断义诊条件
	 * @param userId
	 * @param doctId
	 * @param ruleId 医生规则主键
	 */
	@Locker(paramExp = "['','$']", key = RedisKeyEnum.FREQUENT_OPERATION_KEY, limitTime = 300, noGetMsg = "请稍后!")
	private void checkClinic(Long userId,Long doctId, Long ruleId) {
		List<Long> doctors = iInquiryOrderSV.queryClinicTime(userId);
		if(doctors != null ){
			if(doctors.size()>=3) {
				throw new BusinessException("您一周内只能义诊三次");
			}
			for (Long doctor : doctors) {
				if(doctor.equals(doctId)){
					throw new BusinessException("该医生一周内只能义诊一次,换个医生试试");
				}
			}
		}
		//查询义诊规则
		TextRuleEntity textRule = textRuleDao.selectByPrimaryKey(ruleId);
		if (textRule == null || textRule.getLastManTime() == null || textRule.getLastManTime() <= 0){
			throw new BusinessException("该医生已经没有义诊名额啦,换个医生试试");
		}
		textRule.setLastManTime(textRule.getLastManTime()-1);
		textRuleDao.updateByPrimaryKeySelective(textRule);
	}

	/**
	 * 电话问诊，订单设置,此处主要判定设置orderFlowRecord的流转人
	 *
	 * @param inquiryOrderModel
	 * @param doctorStudioId
	 */
	private void callPhysicianVisitsSet(InquiryOrderParam inquiryOrderModel, OrderFlowRecordEntity orderFlowRecord, Long doctorStudioId) {
		Date date = inquiryOrderModel.getAppointTime();
		if (StringUtils.isEmpty(date)) {
			throw new BusinessException("请选择预约时间");
		}
		SimpleDateFormat weekFormat = new SimpleDateFormat("EEEE", Locale.CHINESE);
		SimpleDateFormat hourFormat = new SimpleDateFormat("HH:mm:ss");
		//电话预约条件
		phoneCondition(inquiryOrderModel.getPatientId(), inquiryOrderModel.getAppointTime());
		//格式化得到周
		String week = weekFormat.format(date);
		//格式化得的时分秒
		String hour = hourFormat.format(date);
		//查询当前时间是否不可选
		DoctorPhoneSettingEntity setting = doctorPhoneSettingDao.selectReservationStatus(inquiryOrderModel.getDoctServId(), week, hour);
		if (setting != null && FlagEnum.NO.getKey().equals(setting.getNotFalg())) {
			throw new BusinessException("该时间已被预约");
		}
		//改医生预约时间表预约状态不可预约
		doctorPhoneSettingDao.updateNotFlag(inquiryOrderModel.getDoctServId(), week, hour);
		// 电话问诊只设置医生ID
		orderFlowRecord.setDoctorId(inquiryOrderModel.getDoctId());
	}

	/**
	 * 电话预约限制
	 */
	private void phoneCondition(Long patientId, Date time) {
		//1.1 是否是同个医生?

		//1.2 相同时间段的预约
		InquiryOrderEntity model = InquiryOrderEntity
				.builder()
				.patientId(patientId)
				.ioType(InquiryOrderIoTypeEnum.TELEPHONE_COUNSELING.getKey())
				.ioState( InquiryOrderStateEnum.WAIT_EFFECTIVE.getKey())
				.paymentState(InquiryOrderPaymentStateEnum.HAVE_TO_PAY.getKey())
				.appointTime(time)
				.build();
		List<InquiryOrderEntity> order = iInquiryOrderSV.selectList(model);
		if (order.size() != 0) {
			throw new BusinessException("您已经有当天时间段的电话问诊预约");
		}
		int count = iInquiryOrderSV.selectCountPh(patientId, time);
		Integer val = sysConfigSV.getValueByKey(Constants.SysConfigKey.PHONE_ORDER_DAY_COUNT, Integer::new);
		if (count > val) {
			throw new BusinessException("当天电话预约不能超过'" + val + "'人");
		}
	}

	@Override
	public List<OpenServiceListVo> openServiceList(Long doctorId) {
		List<OpenServiceListVo> openServiceList = mapper.openServiceList(doctorId);
		return openServiceList;
	}


	/**
	 * 默认三条电话咨询规则数据   (已注释)
	 *
	 * @return
	 */
	@Override
	public List<PhoneRuleEntity> getDefaultPhoneRule() {
		List<PhoneRuleEntity> list = phoneRuleDao.getDefaultPhoneRule();
		return list;
	}

	@Override
	public int upDefaultPhoneRule(Long phoneRuleId) {
		return 0;
	}

	/***
	 * 新增电话规则更改规则对应单价  或者是新增规则和单价 统一接口
	 * @param doctPhoneRuleItemVo
	 * @return
	 */
	@Override
	public int upPhoneRuleAndPrice(DoctPhoneRuleItemVo doctPhoneRuleItemVo) {
		/*1、新增该表记录时，则新增记录时生效时间为当前时间；
		 *  2、修改该表时，则该该记录失效时间改为23:59:59，并新增一条新纪录，并将生效时间设置为次日凌晨00:00:00；
		 *  3、定时任务定期扫描，将失效时间小于当天00:00:00的记录标位失效，
		 *  并将有效时间大于等于当天00:00:00的记录标位有效。
		 *(千万不要轻易动,动了会出事!!)
		 */
		Date date = null;
		int rows = 0;
		Long phoneRuleId = 0L;
		Long docServId = 0L;

		//id判断医生是否有该条服务项
		DoctorServiceItemEntity doctorServiceItem = doctPhoneRuleItemVo.getDoctorServiceItem();
		List<PhoneRuleModel> models = doctPhoneRuleItemVo.getPhoneRuleModels();
		List<DoctorPhoneSettingModel> doctorPhoneSettingModels = doctPhoneRuleItemVo.getDoctorPhoneSettingModels();
		if (doctorServiceItem.getId() != null) {
			mapper.updateByPrimaryKeySelective(doctorServiceItem);
			rows = phoneSetting(doctorPhoneSettingModels);
		} else {
			//第一次开通
			if (models.isEmpty() && FlagEnum.IS.getKey().equals(doctorServiceItem.getIsOpen())) {
				throw new BusinessException("请设置问诊单价");
			} else if (FlagEnum.IS.getKey().equals(doctorServiceItem.getIsOpen()) && doctorPhoneSettingModels.isEmpty()) {
				throw new BusinessException("请至少设置一个预约时间段");
			}
			mapper.insertSelective(doctorServiceItem);
			docServId = doctorServiceItem.getId();
			for (PhoneRuleModel model : models) {
				model.setDocServId(docServId);
			}
			for (DoctorPhoneSettingEntity phoneSetting : doctorPhoneSettingModels) {
				phoneSetting.setDocServId(docServId);
			}
			rows = phoneSetting(doctorPhoneSettingModels);
		}
		Long serId = doctorServiceItem.getId();

		DoctorServicePriceEntity effective = doctorServicePriceDao.selectOneByExample(
				TK.select(DoctorServicePriceEntity.class).limit(1)
						.where()
						.andEqualTo(DoctorServicePriceEntity::getDoctId, doctorServiceItem.getDoctId())
						.andEqualTo(DoctorServicePriceEntity::getSeriLabel, DoctorServiceItemEnum.CALL_PHYSICIAN_VISITS.getKey())
						.andEqualTo(DoctorServicePriceEntity::getState, FlagEnum.IS.getKey()).end());
		if (models.isEmpty() && null == effective && FlagEnum.IS.getKey().equals(doctorServiceItem.getIsOpen())) {
			throw new BusinessException("请设置问诊单价");
		} else if (FlagEnum.IS.getKey().equals(doctorServiceItem.getIsOpen())
				&& doctorPhoneSettingModels.isEmpty() && phoneEffectiveState(serId) == 0) {
			throw new BusinessException("请至少设置一个预约时间段");
		} else if (models.isEmpty() && FlagEnum.NO.getKey().equals(doctorServiceItem.getIsOpen())) {
			return 1;
		}

		/*
		 *  判断是否是第一次设置单价(条件 规则id !null 单价id null)
		 */
		//不变值判断?
		for (PhoneRuleModel phoneRuleModel : models) {
			boolean flag = phoneRuleModel.getId() != null
					&& null == phoneRuleModel.getPriceId();
			if (flag) {
				DoctorServicePriceEntity servicePrice = new DoctorServicePriceEntity();
				servicePrice.setState("01");
				servicePrice.setDoctId(doctorServiceItem.getDoctId());
				servicePrice.setSeriLabel(DoctorServiceItemEnum.CALL_PHYSICIAN_VISITS.getKey());
				servicePrice.setRuleId(phoneRuleModel.getId());
				servicePrice.setDspPrice(phoneRuleModel.getDspPrice());
				servicePrice.setCreateTime(new Date());
				servicePrice.setValidTime(new Date());
				rows = doctorServicePriceDao.insertSelective(servicePrice);
				//Long priceId =  servicePrice.getId();
				//return rows;
			}
			/* 判断是否是新增规则与单价  (新增条件规则id null 单价id null)
			 * 新增的规则及单价 当前时间生效
			 */
			boolean flag2 = null == phoneRuleModel.getId()
					&& null == phoneRuleModel.getPriceId();
			if (flag2) {
				phoneRuleModel.setIsDefault("00");
				phoneRuleDao.insertSelective(phoneRuleModel.covert());

				//新增价钱表数据  非空判断下 防止用户没有设置单价
				if (null == phoneRuleModel.getDspPrice() || BigDecimal.ZERO.equals(phoneRuleModel.getDspPrice())) {
					throw new BusinessException("请设置问诊价格");
				} else {
					phoneRuleId = phoneRuleModel.getId();
					DoctorServicePriceEntity servicePrice = new DoctorServicePriceEntity();
					servicePrice.setRuleId(phoneRuleId);
					servicePrice.setDoctId(doctorServiceItem.getDoctId());
					servicePrice.setSeriLabel(DoctorServiceItemEnum.CALL_PHYSICIAN_VISITS.getKey());
					servicePrice.setDspPrice(phoneRuleModel.getDspPrice());
					servicePrice.setCreateTime(new Date());
					servicePrice.setValidTime(new Date());
					servicePrice.setState("01");
					rows = doctorServicePriceDao.insertSelective(servicePrice);
				}
				// return rows;

			} else {
				/*
				 *判断是更改单价 (条件  规则id !null 单价id !null  服务项id !=null)
				 */

				//查询当前规则对用价钱   查询当下修改价格是否是第一次修改  第一次则结果为null 第二次则不为null  之前(待生效)
				DoctorServicePriceEntity price =
						doctorServicePriceDao.selectCurrPrice(doctorServiceItem.getDoctId(), phoneRuleModel.getId());
				//doctorServicePriceDao.selectById(phoneRuleModel.getPriceId());


				DoctorServicePriceEntity beforePrice =
						//doctorServicePriceDao.selectCurrPrice(phoneRuleModel.getDocServId(),phoneRuleModel.getId());
						doctorServicePriceDao.selectByPrimaryKey(phoneRuleModel.getPriceId());

				DoctorServicePriceEntity servicePrice = new DoctorServicePriceEntity();
				//第一次更改在使用中的单价  需要新增一条并设置生效凌晨  如果价钱相等不操作

				if (beforePrice != null && null == price
						&& phoneRuleModel.getDspPrice().doubleValue() != beforePrice.getDspPrice().doubleValue()) {
					//修改单价时，则之前录失效时间改为23:59:59，；
					beforePrice.setInvalidTime(getInvalidTime());
					//更改上次失效时间为 23:59:58
					doctorServicePriceDao.updateByPrimaryKeySelective(beforePrice);
					//phoneRuleDao.updateByIdSelective(phoneRuleModel);
					//并新增一条新纪录，并将生效时间设置为次日凌晨00:00:00 状态置为失效 "00"
					servicePrice.setDoctId(doctorServiceItem.getDoctId());
					servicePrice.setSeriLabel(DoctorServiceItemEnum.CALL_PHYSICIAN_VISITS.getKey());
					servicePrice.setRuleId(phoneRuleModel.getId());
					servicePrice.setDspPrice(phoneRuleModel.getDspPrice());
					servicePrice.setState("00");
					servicePrice.setValidTime(getValidTime());
					rows = doctorServicePriceDao.insertSelective(servicePrice);
					//第二次设置单价 直接按规则id和服务id修改
				} else if (price != null) {
					//当前
					servicePrice.setId(price.getId());
					servicePrice.setDspPrice(phoneRuleModel.getDspPrice());
					rows = doctorServicePriceDao.updateByPrimaryKeySelective(servicePrice);
				}
			}
		}
		return rows;

	}

	/***
	 * 电话相关设置是否完整
	 * @param doctServId
	 * @return
	 */
	@Override
	public int phoneEffectiveState(Long doctServId) {
		DoctorPhoneSettingEntity sets = doctorPhoneSettingDao.selectOneByExample(
				TK.select(DoctorPhoneSettingEntity.class).limit(1)
						.where().andEqualTo(DoctorPhoneSettingEntity::getDocServId, doctServId).end());
		if (null == sets) {
			return 0;
			//throw new BusinessException("请至少设置一个预约时间段");
		} else {
			return 1;
		}

	}

	/**
	 * 预约 电话时间设置
	 *
	 * @param doctorPhoneSettingModels
	 * @return
	 */
	@Override
	public int phoneSetting(List<DoctorPhoneSettingModel> doctorPhoneSettingModels) {
		int rows = 0;
		for (DoctorPhoneSettingModel dps : doctorPhoneSettingModels) {
			dps.setCreateTime(new Date());
			dps.setNotFalg(FlagEnum.IS.getKey());
			//没有id 新增
			if (null == dps.getId()) {
				rows = doctorPhoneSettingDao.insertSelective(dps);
				//有id 且 itemState 为false 取消选择
			} else if (dps.getId() != null && "false".equals(dps.getItemState())) {
				rows = doctorPhoneSettingDao.deleteByPrimaryKey(dps.getId());
			} else {
				rows = 1;
			}
		}
		return rows;
	}

	@Override
	public List<PhoneAppointmentTimeVo> getPhoneSets(Long docServId) {
		List<PhoneAppointmentTimeVo> list = doctorPhoneSettingDao.getPhoneSets(docServId);
		return list;
	}

	/**
	 * 义诊设置
	 *
	 * @param textRuleModel
	 * @return
	 */
	@Override
	public int freeClinic(TextRuleParam textRuleModel, Long doctId) {
		//判断 当前是否有义诊
		DoctorServicePriceVo clinicPrice = doctorServicePriceDao.clinicService(doctId);
		if (clinicPrice != null) {
			throw new BusinessException("30日内只能开展一次义诊");
		}
		int rows = 0;
		//1.1  写入规则表
		textRuleModel.setTrType(RuleTypeEnum.YIZHEN_RULES.getKey());
		textRuleModel.setIsDefault(FlagEnum.NO.getKey());
		textRuleModel.setLastManTime(textRuleModel.getManTime());
		textRuleDao.insertSelective(textRuleModel.covert());
		//1.2 写入单价表
		DoctorServicePriceEntity price = new DoctorServicePriceEntity();
		price.setDoctId(doctId);
		price.setSeriLabel(DoctorServiceItemEnum.BY_INQUIRING.getKey());
		price.setRuleId(textRuleModel.getId());
		price.setDspPrice(textRuleModel.getDspPrice());
		price.setState(FlagEnum.NO.getKey());
		price.setCreateTime(new Date());
		price.setValidTime(time(textRuleModel.getFreeClinicDate(), false));
		price.setInvalidTime(time(textRuleModel.getFreeClinicDate(), true));
		rows = doctorServicePriceDao.insertSelective(price);
		return rows;
	}

	/**
	 * 时间格式
	 *
	 * @param date
	 * @return
	 */
	private Date time(Date date, boolean bool) {
		TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
		calendar.setTime(date);
		if (bool) {
			calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + 31);
		}
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 义诊服务修改
	 *
	 * @param textRuleModel
	 * @return
	 */
	@Override
	public int upFreeClinic(TextRuleParam textRuleModel, Long doctId) {
		//判断义诊服务是否生效
		DoctorServicePriceVo priceVo = doctorServicePriceDao.freeClinicPrice(null, null, null, textRuleModel.getPriceId()).get(0);
		if (priceVo != null && FlagEnum.IS.getKey().equals(priceVo.getState())) {
			throw new BusinessException("已经开始不可更改");
		}

		int rows = 0;
		//1.1  更改规则
		textRuleModel.setLastManTime(textRuleModel.getManTime());
		textRuleDao.updateByPrimaryKeySelective(textRuleModel.covert());
		//1.2 更改单价表
		DoctorServicePriceEntity price = new DoctorServicePriceEntity();
		price.setId(textRuleModel.getPriceId());
		price.setDspPrice(textRuleModel.getDspPrice());
		price.setValidTime(time(textRuleModel.getFreeClinicDate(), false));
		rows = doctorServicePriceDao.updateByPrimaryKeySelective(price);
		return rows;
	}

	/**
	 * 建立通讯录关系 问诊患者 全部患者
	 *
	 * @param
	 * @param
	 */
	public void createAddressBook(InquiryOrderParam model) {

		//查询对应group主键
		long allPatientId = 0;
		long inquiryId = 0;
		List<AddressGroupEntity> addressGroup = addressGroupDao.selectByDoctId(model.getDoctId());

		for (AddressGroupEntity address : addressGroup) {
			/*if (SystemGroupEnum.PATIENT.ALL.getName().equals(address.getAlgName())) {
				allPatientId = address.getId();
				selectRelation(allPatientId, model.getUserId(), model.getPatientId());

			}*/
			if (SystemGroupEnum.PATIENT.INQUIRY.getName().equals(address.getAlgName())) {
				inquiryId = address.getId();
				selectRelation(inquiryId, model.getUserId(), model.getPatientId());
			}
		}
	}

	/**
	 * 查询是否存在通讯录的关系
	 *
	 * @return
	 */
	private void selectRelation(Long algId, Long userId, Long patientId) {
		//查询患者看是否是本人还是亲属
		//查询是否已经有关系
		AddressListEntity a = addressListDao.selectOneByExample(
				TK.select(AddressListEntity.class).where().andEqualTo(AddressListEntity::getAlgId, algId)
						.andEqualTo(AddressListEntity::getUserId, patientId).end());
		AddressListEntity addressList = null;
		if (null == a) {
			//插入关系表
			addressList = new AddressListEntity();
			addressList.setAlgId(algId);
			addressList.setUserId(patientId);
			//患者
			addressList.setIdType(AddressListIdTypeEnum.IN_PATIENTS_WITH.getKey());
			addressList.setCreateTime(new Date());
			addressListDao.insertSelective(addressList);
		}
	}

	/**
	 * 优惠券判断
	 */
	@Override
	public Map<String, BigDecimal> couponUse(InquiryOrderParam inquiryOrderModel) {

		if (null == inquiryOrderModel.getPriceId()) {
			throw new BusinessException("价格id不能为空");
		}
		// 1.1单价id查询的单价
		DoctorServicePriceEntity price = doctorServicePriceDao.selectByPrimaryKey(inquiryOrderModel.getPriceId());

		BigDecimal payPrice = price.getDspPrice();
		Map<String, BigDecimal> map = null;
		BigDecimal aftDis = BigDecimal.valueOf(0);
		BigDecimal discountAmount = BigDecimal.valueOf(0);
		if (inquiryOrderModel.getRelId() != null) {
			//查询优惠券记录
			CouponReceiveRecordEntity receiveRecord = receiveRecordSV.selectById(inquiryOrderModel.getRelId());
			Long couponId = receiveRecord.getCouponId();
			CouponEntity coupon = iCouponSV.selectById(couponId);
			String theType = coupon.getTheType();
			String toSb = coupon.getToSb();
			//判断是否对应优惠券(图文使用图文,电话使用电话)
			String ioType = inquiryOrderModel.getIoType();
			if (ioType != null) {
				InquiryOrderIoTypeEnum enumByCode = DictEnum.valueOfEnum(InquiryOrderIoTypeEnum.class, inquiryOrderModel.getIoType());
				switch (enumByCode) {
					case BY_CONSULTING:
						if (DoctorServiceItemEnum.BY_INQUIRING.getKey().equals(toSb)) {
							break;
						}
					case TELEPHONE_COUNSELING:
						if (DoctorServiceItemEnum.CALL_PHYSICIAN_VISITS.getKey().equals(toSb)) {
							break;
						}
					case VIDEO_CONSULTATION:
						if (DoctorServiceItemEnum.CALL_VIDEO_VISITS.getKey().equals(toSb)) {
							break;
						}
					case PRVIVATE_DOCTOR:
						if (DoctorServiceItemEnum.PRIVATE_DOCTORS.getKey().equals(toSb)) {
							break;
						}
					default:
						throw new BusinessException("请选择对应服务的优惠券");

				}
			}
			//折扣限制额
			BigDecimal discountMoney = (null == coupon.getDiscountMoney()) ? BigDecimal.ZERO : coupon.getDiscountMoney();
			String remark = null;
			if (CouponTypeEnum.DISCOUNT_COUPONS.getKey().equals(theType)) {
				//折扣券
				BigDecimal discount = coupon.getDiscount();
				// todo 此处取discountName
				BigDecimal discountName = coupon.getDiscount();
				//实际支付额
				aftDis = payPrice.multiply(discount);
				//折扣金额
				discountAmount = payPrice.subtract(aftDis);
				String str = null;
				if (BigDecimal.ZERO.equals(discountMoney) || discountAmount.doubleValue() < discountMoney.doubleValue()) {
					str = "未";
				} else if (discountAmount.doubleValue() > discountMoney.doubleValue()) {
					str = "";
					//超出折扣额度  直接减去最大折扣额
					aftDis = payPrice.subtract(discountMoney);
					discountAmount = discountMoney;
				}
				//应付款
				inquiryOrderModel.setPayableAmount(payPrice);
				//实付款
				inquiryOrderModel.setPaymentPrice(aftDis);
				remark = String.format("使用“%s”优惠劵,订单金额%s元,实际支付金额%s元,折扣金额%s元,%s达到最大折扣金额%s元",
						discountName, payPrice, aftDis, discountAmount, str, discountMoney);
				logger.info("折扣优惠券使用备注=====>" + remark);
				inquiryOrderModel.setPayRemark(remark);
			} else if (CouponTypeEnum.WITH_REDUCED_SECURITIES.getKey().equals(theType) || CouponTypeEnum.A_VOUCHER.getKey().equals(theType)) {
				//满减券    满额减扣金额
				BigDecimal fullMoney = coupon.getFullMoney();
				//满额金额 0无限制
				BigDecimal fullLimit = coupon.getFullLimit();

				if (BigDecimal.ZERO.equals(fullLimit) || payPrice.doubleValue() >= fullLimit.doubleValue()) {
					//实付额
					aftDis = payPrice.subtract(fullMoney);
					//减扣额
					discountAmount = payPrice.subtract(aftDis);
					inquiryOrderModel.setPayableAmount(payPrice);
					inquiryOrderModel.setPaymentPrice(aftDis);
					remark = String.format("使用“满%s元减%s元”优惠劵,订单金额%s元,实际支付金额%s元",
							fullLimit, fullMoney, payPrice, aftDis);
					logger.info("满减优惠券使用备注=====>" + remark);
					inquiryOrderModel.setPayRemark(remark);
				} else if (!BigDecimal.ZERO.equals(fullLimit) && fullLimit.doubleValue() > payPrice.doubleValue()) {
					throw new BusinessException(String.format("支付金额未达到减扣限额%s元", fullLimit));
				}
			}
		} else {
			inquiryOrderModel.setPaymentPrice(payPrice);
			inquiryOrderModel.setPayableAmount(payPrice);
			logger.info("未使用优惠券");

		}
		map = new HashMap<>(2);
		map.put("paymentPrice", aftDis);
		map.put("discountAmount", discountAmount);
		return map;
	}

	@Override
	public OrderVo samePatientLimit(Long patientId, Long doctId) {
		OrderVo orderVo = iInquiryOrderSV.samePatientLimit(patientId, doctId);
		if (orderVo != null) {
			return orderVo;
		}
		return null;
	}
}
